package health_system.health_system.service.impl;

import health_system.health_system.entity.LoginRecord;
import health_system.health_system.entity.User;
import health_system.health_system.repository.LoginRecordRepository;
import health_system.health_system.repository.UserRepository;
import health_system.health_system.service.LoginRecordService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * 登录记录服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginRecordServiceImpl implements LoginRecordService {

    private final LoginRecordRepository loginRecordRepository;
    private final UserRepository userRepository;

    // 正则表达式用于识别移动设备的用户代理
    private static final Pattern MOBILE_PATTERN = Pattern.compile("(?i).*?mobile|android|iphone|ipod|blackberry|windows\\s+phone.*?");
    // 正则表达式用于识别平板设备的用户代理
    private static final Pattern TABLET_PATTERN = Pattern.compile("(?i).*?tablet|ipad|kindle|silk.*?");

    @Override
    @Transactional
    public LoginRecord recordLogin(User user, HttpServletRequest request,
                                   LoginRecord.LoginStatus loginStatus, String failReason) {
        log.debug("Recording login for user {}, status: {}", user.getUsername(), loginStatus);
        
        // 解析HTTP请求中的信息
        String ipAddress = getClientIpAddress(request);
        String userAgent = request.getHeader("User-Agent");
        String sessionId = request.getSession(true).getId();
        
        // 解析设备信息
        LoginRecord.DeviceType deviceType = detectDeviceType(request);
        String deviceName = parseDeviceName(userAgent);
        String operatingSystem = parseOperatingSystem(userAgent);
        String browser = parseBrowser(userAgent);
        
        // 解析地理位置（实际应用中可能需要调用IP地理位置服务API）
        String location = resolveLocation(ipAddress);
        
        // 创建登录记录
        LoginRecord loginRecord = LoginRecord.builder()
                .user(user)
                .deviceType(deviceType)
                .deviceName(deviceName)
                .operatingSystem(operatingSystem)
                .browser(browser)
                .ipAddress(ipAddress)
                .location(location)
                .loginStatus(loginStatus)
                .failReason(failReason)
                .loginTime(LocalDateTime.now())
                .sessionId(sessionId)
                .userAgent(userAgent)
                .build();
        
        // 保存登录记录
        return loginRecordRepository.save(loginRecord);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<LoginRecord> getUserLoginRecords(Long userId, Pageable pageable) {
        log.debug("Getting login records for user ID: {}", userId);
        return loginRecordRepository.findByUserIdOrderByLoginTimeDesc(userId, pageable);
    }

    @Override
    @Transactional(readOnly = true)
    public List<LoginRecord> getRecentLoginRecords(Long userId, int limit) {
        log.debug("Getting {} recent login records for user ID: {}", limit, userId);
        
        Optional<User> userOpt = userRepository.findById(userId);
        if (userOpt.isEmpty()) {
            return new ArrayList<>();
        }
        
        User user = userOpt.get();
        PageRequest pageRequest = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "loginTime"));
        return loginRecordRepository.findRecentLoginsByUser(user, pageRequest);
    }

    @Override
    @Transactional(readOnly = true)
    public LoginRecord getLastSuccessfulLogin(Long userId) {
        log.debug("Getting last successful login for user ID: {}", userId);
        
        List<LoginRecord> loginRecords = loginRecordRepository.findLastSuccessfulLogin(
                userId, PageRequest.of(0, 1));
        
        return loginRecords.isEmpty() ? null : loginRecords.get(0);
    }

    @Override
    @Transactional(readOnly = true)
    public long countRecentFailedLogins(Long userId, int minutes) {
        log.debug("Counting recent failed logins for user ID: {} in the last {} minutes", userId, minutes);
        
        LocalDateTime startTime = LocalDateTime.now().minusMinutes(minutes);
        return loginRecordRepository.countFailedLoginAttempts(userId, startTime);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean detectSuspiciousActivity(Long userId, String ipAddress) {
        log.debug("Detecting suspicious activity for user ID: {} from IP: {}", userId, ipAddress);
        
        // 1. 检查短时间内的登录失败次数
        final int THRESHOLD_MINUTES = 30;
        final int THRESHOLD_FAILURES = 5;
        long recentFailures = countRecentFailedLogins(userId, THRESHOLD_MINUTES);
        
        if (recentFailures >= THRESHOLD_FAILURES) {
            log.warn("Detected suspicious activity: {} failed login attempts in the last {} minutes for user ID: {}", 
                    recentFailures, THRESHOLD_MINUTES, userId);
            return true;
        }
        
        // 2. 检查是否是新IP地址登录
        LoginRecord lastLogin = getLastSuccessfulLogin(userId);
        if (lastLogin != null && !ipAddress.equals(lastLogin.getIpAddress())) {
            // 如果是不同的IP，可以进一步分析地理位置是否异常
            String newLocation = resolveLocation(ipAddress);
            String lastLocation = lastLogin.getLocation();
            
            // 如果地理位置差异很大，可以标记为可疑
            // 注意：这里需要实际的地理位置距离计算，简化处理
            if (lastLocation != null && newLocation != null && !lastLocation.equals(newLocation)) {
                log.warn("Detected suspicious activity: login from new location. User ID: {}, New location: {}, Last location: {}", 
                        userId, newLocation, lastLocation);
                return true;
            }
        }
        
        return false;
    }

    @Override
    @Transactional(readOnly = true)
    public List<String> getUserDevices(Long userId) {
        log.debug("Getting devices for user ID: {}", userId);
        
        // 创建一个分页请求，获取最近的100条登录记录
        Pageable pageable = PageRequest.of(0, 100, Sort.by(Sort.Direction.DESC, "loginTime"));
        Page<LoginRecord> loginRecords = loginRecordRepository.findByUserIdOrderByLoginTimeDesc(userId, pageable);
        
        // 提取不同的设备信息
        List<String> devices = new ArrayList<>();
        loginRecords.forEach(record -> {
            String deviceInfo = record.getDeviceName();
            if (StringUtils.hasText(deviceInfo) && !devices.contains(deviceInfo)) {
                devices.add(deviceInfo);
            }
        });
        
        return devices;
    }

    @Override
    @Transactional(readOnly = true)
    public Page<LoginRecord> getLoginRecordsBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable) {
        log.debug("Getting login records between {} and {}", startTime, endTime);
        
        // 这里需要实现一个新的查询方法或使用动态查询
        // 简化实现，直接返回所有记录
        return loginRecordRepository.findAll(pageable);
    }

    @Override
    public LoginRecord.DeviceType detectDeviceType(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        if (userAgent == null) {
            return LoginRecord.DeviceType.UNKNOWN;
        }
        
        // 先检查是否是平板设备
        if (TABLET_PATTERN.matcher(userAgent).matches()) {
            return LoginRecord.DeviceType.TABLET;
        }
        
        // 再检查是否是移动设备
        if (MOBILE_PATTERN.matcher(userAgent).matches()) {
            return LoginRecord.DeviceType.MOBILE;
        }
        
        // 默认为桌面设备
        return LoginRecord.DeviceType.DESKTOP;
    }

    @Override
    public String resolveLocation(String ipAddress) {
        log.debug("Resolving location for IP: {}", ipAddress);
        
        // 实际应用中，这里应该调用IP地理位置解析服务
        // 例如：MaxMind GeoIP2、ip-api.com、ipinfo.io等
        
        // 简化实现，返回未知位置
        if (ipAddress.startsWith("192.168.") || ipAddress.equals("127.0.0.1")) {
            return "本地网络";
        }
        
        return "未知位置"; // 在实际应用中应该返回真实地理位置
    }
    
    /**
     * 从User-Agent解析设备名称
     */
    private String parseDeviceName(String userAgent) {
        if (userAgent == null) {
            return "Unknown Device";
        }
        
        // 简单的解析逻辑，实际应用中可能需要更复杂的解析库
        if (userAgent.contains("iPhone")) {
            return "iPhone";
        } else if (userAgent.contains("iPad")) {
            return "iPad";
        } else if (userAgent.contains("Android")) {
            if (userAgent.contains("SM-")) {
                // Samsung设备
                String model = extractSamsungModel(userAgent);
                return "Samsung " + model;
            } else if (userAgent.contains("Pixel")) {
                return "Google Pixel";
            } else {
                return "Android Device";
            }
        } else if (userAgent.contains("Windows")) {
            return "Windows PC";
        } else if (userAgent.contains("Macintosh") || userAgent.contains("Mac OS")) {
            return "Mac";
        } else if (userAgent.contains("Linux")) {
            return "Linux Device";
        }
        
        return "Unknown Device";
    }
    
    /**
     * 从User-Agent解析操作系统
     */
    private String parseOperatingSystem(String userAgent) {
        if (userAgent == null) {
            return "Unknown OS";
        }
        
        // 简单的解析逻辑
        if (userAgent.contains("Windows NT 10.0")) {
            return "Windows 10";
        } else if (userAgent.contains("Windows NT 6.3")) {
            return "Windows 8.1";
        } else if (userAgent.contains("Windows NT 6.2")) {
            return "Windows 8";
        } else if (userAgent.contains("Windows NT 6.1")) {
            return "Windows 7";
        } else if (userAgent.contains("Windows NT")) {
            return "Windows";
        } else if (userAgent.contains("iPhone OS")) {
            return extractIOSVersion(userAgent);
        } else if (userAgent.contains("iPad; CPU OS")) {
            return extractIOSVersion(userAgent);
        } else if (userAgent.contains("Mac OS X")) {
            return extractMacOSVersion(userAgent);
        } else if (userAgent.contains("Android")) {
            return extractAndroidVersion(userAgent);
        } else if (userAgent.contains("Linux")) {
            return "Linux";
        }
        
        return "Unknown OS";
    }
    
    /**
     * 从User-Agent解析浏览器信息
     */
    private String parseBrowser(String userAgent) {
        if (userAgent == null) {
            return "Unknown Browser";
        }
        
        // 简单的解析逻辑
        if (userAgent.contains("Chrome") && !userAgent.contains("Chromium") 
                && !userAgent.contains("Edge") && !userAgent.contains("Edg/") 
                && !userAgent.contains("OPR") && !userAgent.contains("Opera")) {
            return extractBrowserVersion(userAgent, "Chrome");
        } else if (userAgent.contains("Firefox") && !userAgent.contains("Seamonkey")) {
            return extractBrowserVersion(userAgent, "Firefox");
        } else if (userAgent.contains("Safari") && !userAgent.contains("Chrome") 
                && !userAgent.contains("Chromium") && !userAgent.contains("Android")) {
            return extractBrowserVersion(userAgent, "Safari");
        } else if (userAgent.contains("Edge") || userAgent.contains("Edg/")) {
            return "Microsoft Edge";
        } else if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            return "Internet Explorer";
        } else if (userAgent.contains("OPR") || userAgent.contains("Opera")) {
            return "Opera";
        }
        
        return "Unknown Browser";
    }
    
    /**
     * 提取iOS版本号
     */
    private String extractIOSVersion(String userAgent) {
        // 例如："iPhone OS 14_7_1 like Mac OS X"
        String pattern = "iPhone OS ([0-9_]+)";
        if (userAgent.contains("iPad")) {
            pattern = "CPU OS ([0-9_]+)";
        }
        
        java.util.regex.Matcher matcher = Pattern.compile(pattern).matcher(userAgent);
        if (matcher.find()) {
            String version = matcher.group(1).replace("_", ".");
            return "iOS " + version;
        }
        
        return "iOS";
    }
    
    /**
     * 提取macOS版本号
     */
    private String extractMacOSVersion(String userAgent) {
        // 例如："Mac OS X 10_15_7"
        java.util.regex.Matcher matcher = Pattern.compile("Mac OS X ([0-9_]+)").matcher(userAgent);
        if (matcher.find()) {
            String version = matcher.group(1).replace("_", ".");
            return "macOS " + version;
        }
        
        return "macOS";
    }
    
    /**
     * 提取Android版本号
     */
    private String extractAndroidVersion(String userAgent) {
        // 例如："Android 11"
        java.util.regex.Matcher matcher = Pattern.compile("Android ([0-9\\.]+)").matcher(userAgent);
        if (matcher.find()) {
            String version = matcher.group(1);
            return "Android " + version;
        }
        
        return "Android";
    }
    
    /**
     * 提取Samsung设备型号
     */
    private String extractSamsungModel(String userAgent) {
        // 例如："SM-G975F"
        java.util.regex.Matcher matcher = Pattern.compile("SM-([A-Z0-9]+)").matcher(userAgent);
        if (matcher.find()) {
            return matcher.group(1);
        }
        
        return "Galaxy";
    }
    
    /**
     * 提取浏览器版本号
     */
    private String extractBrowserVersion(String userAgent, String browser) {
        String pattern = browser + "/([0-9\\.]+)";
        java.util.regex.Matcher matcher = Pattern.compile(pattern).matcher(userAgent);
        if (matcher.find()) {
            String version = matcher.group(1);
            return browser + " " + version;
        }
        
        return browser;
    }
    
    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        
        // 如果是多级代理，获取第一个IP地址
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        
        return ip;
    }
} 